package ua.tach.shortl.logic;

import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;

public class FlyingRail {
	private KindOfRail fl ;
	private Vector2 compv = new Vector2();
	private int stateTimer = 0;

	enum stFlRail {
		sNONE,
		sBEGIN,
		sDRAGGED,
		sPLACE,
		sCLOSE
	};
	private stFlRail fstate;

	enum stFlRailEvent {
		sUP,
		sDOWN,
		sDRAG,
		sTIMER,
		sDROP
	};

	public FlyingRail() {
		fl = rsel[0];
		fstate = stFlRail.sNONE;
	}

	private class KindOfRail {
		private int typeIndex;
		private float rotate;
		private boolean correct;
		private Point shift;
		// correction value to find second end coordinate
		private Point otherEnd;
		// Connect direction on both sides
		private int firstDir;
		private int otherDir;
		private float blink;
		private float blinkDir;

		public KindOfRail( int index, float r, Point oth, int d1, int d2) {
			typeIndex = index;
			rotate = r;
			shift = new Point();
			otherEnd = oth;
			firstDir = d1;
			otherDir = d2;
			blinkDir = 0.1f;
			blink = 0.5f;
		}

		public Rail getNew() {
			Point pp = new Point(shift.x, shift.y);
			Rail res;
			if(typeIndex==0)
				res = new RailRound(pp, rotate, true);
			else
				res = new RailStraight(pp, rotate, true);

			res.swChange(Country.links[ shift.getIndex() ].getSw(firstDir),
						Country.links[ shift.getIndex(otherEnd) ].getSw(otherDir));
			return res;
		}

		public void move(Vector2 v) {
			shift.x = Math.round(v.x-0.25f);
			shift.y = Math.round(v.y-0.25f);
        	//System.out.println(" 1= "+ shift.x +"," + shift.y + " 2= "+ (shift.x+otherEnd.x) +"," + (shift.y+otherEnd.y) + " ind " + typeIndex + " rot " + rotate);
			if (shift.isCorrectCoordinate(otherEnd)) {
				if(Country.links[ shift.getIndex() ].isFree(firstDir) &&
						Country.links[ shift.getIndex(otherEnd) ].isFree(otherDir))
					correct = true;
				else
					correct = false;
			} else {
				correct = false;
			}
		}

		public void tick() {
			blink += blinkDir;
			if (blink > .81f)
				blinkDir = -0.1f;
			else if (blink < 0.21f)
				blinkDir = 0.1f;
		}

		public void render(GL10 gl) {
			if (typeIndex == -1) return;
			gl.glPushMatrix();
			gl.glEnable(GL10.GL_BLEND);
			Rail.texture[typeIndex].bind();
			if(correct)
				gl.glColor4f(0, 0.7f, 0, blink);
			else
				gl.glColor4f(0.7f, 0, 0, blink);

			gl.glTranslatef(shift.x, 0, shift.y);
			gl.glRotatef(rotate, 0, rotate, 0);
			Rail.mesh[typeIndex].render(GL10.GL_TRIANGLES);
			gl.glDisable(GL10.GL_BLEND);
			gl.glColor4f(1.f, 1.f, 1.f, 1.f);
			gl.glPopMatrix();
		}
	}

	private KindOfRail[] rsel = {
			new KindOfRail(-1,0, new Point(0,0), 0, 0),
			new KindOfRail(1,0, new Point(1,0), 0, 2),
			new KindOfRail(1,90, new Point(0,-1), 3, 1),
			new KindOfRail(0,0, new Point(-1,1), 2, 3),
			new KindOfRail(0,90, new Point(1,1), 1, 2),
			new KindOfRail(0,180, new Point(1,-1), 0, 1),
			new KindOfRail(0,270, new Point(-1,-1), 3, 0)
	};

	private void setNewFl(int style) {
		System.out.println(" New rail "+style);
		fl = rsel[style];
		fl.move(Country.vect);
	}

	public boolean downCountry(Vector3 v) {
		if (fstate==stFlRail.sPLACE) {
			Country.setvect(v);
			//System.out.println(" old: "+ compv + " new " + Country.vect + "Compare: "+compv.dist2(Country.vect));
			if(compv.dst2(Country.vect) < 0.8f) {
				doFSM(stFlRailEvent.sDOWN, 0);
				return false;
			} else {
				doFSM(stFlRailEvent.sDROP, 0);
				return true;
			}
		} else return true;
	}

	public boolean downFlRail(int style, Vector3 v) {
		Country.setvect(v);
		if (fstate==stFlRail.sPLACE)
			doFSM(stFlRailEvent.sDRAG, style);
		else
			doFSM(stFlRailEvent.sDOWN, style);
		return false;
	}

	public void dragFlRail(Vector3 v) {
		Country.setvect(v);
		doFSM(stFlRailEvent.sDRAG, 0);
	}

	public void upFlRail (Vector3 v) {
		doFSM(stFlRailEvent.sUP, 0);
	}

	public void tick() {
		fl.tick();
		if(stateTimer == 0) return;
		if(stateTimer == 1) {
			doFSM(stFlRailEvent.sTIMER, 0);
		}
		--stateTimer;
	}

	public void render(GL10 gl) {
		fl.render(gl);
	}

	public void doFSM (stFlRailEvent ev, int param) {
		//System.out.println("FSM " +fstate+ ": "+ Country.vect + " ev "+ ev + " par "+ param);
		switch(fstate) {
		case sNONE:
			if (ev == stFlRailEvent.sDOWN && param > 0) {
				stateTimer = 5;
				fstate = stFlRail.sBEGIN;
				setNewFl(param);
			}
			break;
		case sBEGIN:
			if (ev == stFlRailEvent.sTIMER) {
				fstate = stFlRail.sDRAGGED;
			} else if (ev == stFlRailEvent.sUP) {
				stateTimer = 0;
				fstate = stFlRail.sNONE;
			} else if (ev == stFlRailEvent.sDRAG) {
				fl.move(Country.vect);
			}
			break;
		case sDRAGGED:
			if (ev == stFlRailEvent.sDOWN) {
				stateTimer = 5;
				fstate = stFlRail.sBEGIN;
				setNewFl(param);
			} else if (ev == stFlRailEvent.sUP) {
				if(fl.correct) {
					compv.set(Country.vect); // keep position for compare
					fstate = stFlRail.sPLACE;
				} else {
					setNewFl(0);
					fstate = stFlRail.sNONE;
				}
			} else if (ev == stFlRailEvent.sDRAG) {
				fl.move(Country.vect);
			}
			break;
		case sPLACE:
			if (ev == stFlRailEvent.sDOWN) {
				stateTimer = 5;
				fstate = stFlRail.sCLOSE;
			} else if (ev == stFlRailEvent.sDRAG) {
				fl = rsel[param];
				fstate = stFlRail.sDRAGGED;
			} else if (ev == stFlRailEvent.sDROP) {
				fstate = stFlRail.sNONE;
				fl = rsel[0];
			}
			break;
		case sCLOSE:
			if (ev == stFlRailEvent.sTIMER) {
				fstate = stFlRail.sDRAGGED;
			} else if (ev == stFlRailEvent.sUP) {
				fstate = stFlRail.sNONE;
				// Place rail
				Country.addRail(fl.getNew(), fl.otherEnd, fl.firstDir, fl.otherDir);
				Country.bank.buildRail();

				fl = rsel[0];
			}
			break;
		}
	}
}
